#include once <neg32.asm>
;---------------------------------------------------------
__DIVU32:
; 32 bit unsigned division
; DEHL = Dividend, Stack Top = Divisor
; OPERANDS P = Dividend, Q = Divisor => OPERATION => P / Q
; Changes A, BC DE HL B'C' D'E' H'L'
;---------------------------------------------------------
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                 ;- pop hl   ; return address
sta z80_h
pla
sta z80_l
sta z80_d
pla
sta z80_e
tsx                 ;- ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend
lda $0103,x
ldy z80_h
sta z80_h
tya
sta $0103,x
lda $0104,x
ldy z80_l
sta z80_l
tya

__DIVU32START: ; Performs D'E'H'L' / HLDE
; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B)
lda z80_e           ;- push de ; push Lowpart(Q)
pha
lda z80_d
pha
lda z80_e           ;- ex de, hl  ; DE = HL
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
lda #<0              ;- ld hl, 0
sta z80_l
lda #>0
sta z80_h
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
lda z80_c            ;- ld b,c
sta z80_b
lda z80_l            ;- ld c,l
sta z80_c
pla                  ;- pop hl
sta z80_h
pla
sta z80_l
lda z80_e            ;- push de
pha
lda z80_d
pha
lda z80_e            ;- ex de,hl
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
lda #<0              ;- ld hl, 0        ; H'L'HL = 0
sta z80_l
lda #>0
sta z80_h
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                  ;- pop bc          ; Pop HightPart(B) => B = B'C'BC
sta z80_b
pla
sta z80_c
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
lda #32              ;- ld a,32 ; Loop count

__DIV32LOOP:
                     ;- sll c  ; B'C'BC << 1 ; Output most left bit to carry
rol z80_b            ;- rl b
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
rol z80_c            ;- rl c
rol z80_b            ;- rl b
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
                     ;- adc hl,hl
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
                     ;- adc hl,hl
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
                     ;- sbc hl,de
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
lda z80_l            ;- sbc hl,de
sbc z80_e
sta z80_l
lda z80_h
sbc z80_d
sta z80_h
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
jcs __DIV32NOADD     ;- jp nc, __DIV32NOADD  ; use JP inside a loop for being faster
clc               ;- add hl,de
lda z80_l
adc z80_e
sta z80_l
lda z80_h
adc z80_d
sta z80_h
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
                     ;- adc hl, de
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
                     ;- dec bc

__DIV32NOADD:
                     ;- dec a
jne __DIV32LOOP      ;- jp nz, __DIV32LOOP  ; use JP inside a loop for being faster
; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL
lda z80_l            ;- push hl
pha
lda z80_h
pha
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                  ;- pop de
sta z80_d
pla
sta z80_e
lda z80_e            ;- ex de,hl ; D'E'H'L' = 32 bits modulus
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
lda z80_c            ;- push bc
pha
lda z80_b
pha
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                  ;- pop de    ; DE = B'C'
sta z80_d
pla
sta z80_e
lda z80_b            ;- ld h,b
sta z80_h
lda z80_c            ;- ld l,c   ; DEHL = quotient D'E'H'L' = Modulus
sta z80_l
rts                  ;- ret     ; DEHL = quotient, D'E'H'L' = Modulus

__MODU32:    ; 32 bit modulus for 32bit unsigned division
; DEHL = Dividend, Stack Top = Divisor (DE, HL)
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                  ;- pop hl   ; return address
sta z80_h
pla
sta z80_l
pla                  ;- pop de   ; low part
sta z80_d
pla
sta z80_e
tsx                  ;- ex (sp),hl ; CALLEE Convention ; H'L'D'E' => Dividend
lda $0103,x
ldy z80_h
sta z80_h
tya
sta $0103,x
lda $0104,x
ldy z80_l
sta z80_l
tya
sta $104,x
jsr __DIVU32START    ;- call __DIVU32START  ; At return, modulus is at D'E'H'L'

__MODU32START:
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
lda z80_e           ;- push de
pha
lda z80_d
pha
lda z80_l           ;- push hl
pha
lda z80_h
pha
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                 ;- pop hl
sta z80_h
pla
sta z80_l
pla                 ;- pop de
sta z80_d
pla
sta z80_e
rts                 ;- ret

__DIVI32:    ; 32 bit signed division
; DEHL = Dividend, Stack Top = Divisor
; A = Dividend, B = Divisor => A / B
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                 ;- pop hl   ; return address
sta z80_h
pla
sta z80_l
pla                 ;- pop de   ; low part
sta z80_d
pla
sta z80_e
tsx                 ;- ex (sp),hl ; CALLEE Convention ; H'L'D'E' => Dividend
lda $0103,x
ldy z80_h
sta z80_h
tya
sta $0103,x
lda $0104,x
ldy z80_l
sta z80_l
tya
sta $104,x

__DIVI32START:
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
lda z80_d           ;- ld a,d   ; Save sign
sta z80_a
ldx z80_ap          ;- ex af,af'
sta z80_ap
txa
lda z80_d           ;- bit 7, d ; Negative?
cmp #$80
beq *+5             ;- call nz, __NEG32 ; Negates DEHL
jsr __NEG32
lda z80_c           ;- exx    ; Now works with H'L'D'E'
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
ldx z80_ap          ;- ex af,af'
sta z80_ap
txa
eor z80_h           ;- xor h
ldx z80_ap          ;- ex af,af'  ; Stores sign of the result for later
sta z80_ap
txa
lda z80_h           ;- bit 7,h ; Negative?
cmp #$80
lda z80_e           ;- ex de,hl ; HLDE = DEHL
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
beq *+5             ;- call nz,__NEG32
jsr __NEG32
lda z80_e           ;- ex de,hl
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
jsr __DIVU32START   ;- call __DIVU32START
ldx z80_ap          ;- ex af,af' ; Recovers sign
sta z80_ap
txa
and 128             ;- and 128     ; positive?
bne *+3             ;- ret z
rts
jmp __NEG32         ;- jp __NEG32 ; Negates DEHL and returns from there

__MODI32:  ; 32bits signed division modulus
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                 ;- pop hl   ; return address
sta z80_h
pla
sta z80_l
pla                 ;- pop de   ; low part
sta z80_d
pla
sta z80_e
tsx                 ;- ex (sp),hl ; CALLEE Convention ; H'L'D'E' => Dividend
lda $0103,x
ldy z80_h
sta z80_h
tya
sta $0103,x
lda $0104,x
ldy z80_l
sta z80_l
tya
sta $104,x
jsr __DIVI32START   ;- call __DIVI32START
jmp __MODU32START   ;- jp __MODU32START

